/**
* PermissionSpecificator.cs
**/
using System;
using System.Collections.Generic;

using Yawf.Security.Entities;

namespace Yawf.Security {
	public class PermissionSpecificator {
		// Private fields
		private IList<String> publicResources;
		private IDictionary<String, IList<String>> privateResources;
		private bool doCheckPermssionAgainstRole = false;

		public IList<String> PublicResources { get { return publicResources; } set { publicResources = value;} }
		public IDictionary<String, IList<String>> PrivateResources { get { return privateResources; } set { privateResources = value; } }
		public bool DoCheckPermssionAgainstRole { get { return doCheckPermssionAgainstRole; } set { doCheckPermssionAgainstRole = value; } }

		/**
		* Checks wheather a user has permission to a certain resource
		*
		* @param user - User object that has to be checked
		* @param resource Resource that shold be checked
		* @return true if user has permission to resource, false otherwise
		* @see publiguias.framework.authentication.AuthenticationManager#hasPermisssion(publiguias.framework.authentication.entities.User, java.lang.String)
		**/
		public bool HasPermisssion(IUser user, String resource) {
			// Resource is null, always return true, cause user has always permission to nothing
			if (resource == null) {
				return true;
			}

			if (resource.StartsWith("~")) {
				resource = resource.Substring(1);
			}

			// Add / to resource if resource does not have it
			if (!resource.StartsWith("/")) {
				resource = "/" + resource;
			}

			return CheckResource(this.PublicResources, resource) || IsPrivateResource(resource, user);
		}

		/**
		* Checks wheather a user has permission to a certain resource by 
		*
		* @param user - User object that has to be checked
		* @param resource Resource that shold be checked
		* @return true if user has permission to resource, false otherwise
		* @see publiguias.framework.authentication.AuthenticationManager#hasPermisssion(publiguias.framework.authentication.entities.User, java.lang.String)
		**/
		public bool HasRolePermisssion(IUser user, String resource) {
			// Resource is null, always return true, cause user has always permission to nothing
			if (resource == null) {
				return true;
			}

			// Add / to resource if resource does not have it
			if (!resource.StartsWith("/")) {
				resource = "/" + resource;
			}

			return CheckResource(this.PublicResources, resource) || IsPrivateResource(resource, user);
		}

		/**
		* Check weather a user has permssion to a resource
		*
		* @param resource - resource to check
		* @param user - user to get permissions from which we want to check the resource
		* @return true if the user has permissionto this resource, false otherwise
		**/
		private bool IsPrivateResource(String resource, IUser user) {
			IList<IProfile> profiles;
			int i;

			// If no user, then definitly we  dont have permission
			if (user == null) {
				return false;
			}

			profiles = user.Profiles;
			for (i = 0; profiles != null && i < profiles.Count; i++) {
				if (CheckProfile(profiles[i], resource)) {
					return true;
				}
			}

			return false;
		}										// isPrivateResource

		/**
		* Checks if a Profile has permission to a resource
		*
		* @param profile - Profile to check
		* @param resource - Resource to check against
		* @return true if Profile has permission to resource
		*
		**/
		private bool CheckProfile(IProfile profile, String resource) {
			IDictionary<String, IList<String>> privResources;
			IList<IPermission> permissions;
			IList<String> resourcesPaths;
			IPermission permission;
			int i;

			if (profile != null) {
				// Check Permissions of Profile
				privResources = this.PrivateResources;
				permissions = profile.Permissions;
				for (i = 0; permissions != null && i < permissions.Count; i++) {
					permission = permissions[i];
					if (privResources.ContainsKey("" + permission.Id)) {
						resourcesPaths = privResources["" + permission.Id];
						if (resourcesPaths != null && CheckResource(resourcesPaths, resource)) {
							return true;
						}
					}
				}

				// If permission is null & we should check aginst role, eg if role name has permission
				// to private role
				if (permissions == null && DoCheckPermssionAgainstRole) {
					if (privResources.ContainsKey("" + profile.Id)) {
						resourcesPaths = privResources["" + profile.Id];
						if (resourcesPaths != null && CheckResource(resourcesPaths, resource)) {
							return true;
						}
					}
				}
			}

			return false;
		}

		/**
		* Checks weather the resource exists in a list of esources

		* @param publRes - list of resources
		* @param resource - resource to check
		* @return true if resource belongs to a public resource, false otherwise
		**/
		private bool CheckResource(IList<String> publRes, String resource) {
			String publicResource;
			int i;

			for (i = 0; publRes != null && i < publRes.Count; i++) {
				publicResource = publRes[i];
				if (resource.StartsWith(publicResource)) {
					return true;
				}
			}

			return false;
		}									// isPublicResource

	}

}